//==========================================================================
// Copyright (c) 2000-2008,  Elastos, Inc.  All Rights Reserved.
//==========================================================================
#include "namedobj.h"
#include "namedmutex.h"
#include "namedevent.h"
#include "sharedmem.h"
#include "pcentral.h"
#include <aura.h>

#define Lock(hCritical)     do { \
                                AuraCriticalSection_Enter(hCritical); \
                            } while(0)

#define Unlock(hCritical)   do { \
                                AuraCriticalSection_Leave(hCritical); \
                            } while(0)


DLinkNode NamedObject::s_namedHashList[NAMED_HS_SLOTS];
PVoid     NamedObject::s_hListLock = NULL;

STATIC UInt32 NamedHashCode(WString name)
{
    UInt32 h = 0;
    const wchar_t *p;

    for (p = (const wchar_t*)name; *p != L'\0'; p++) {
        h += *p;
    }
    return h & (NAMED_HS_SLOTS - 1);
}

ECode NamedObject::S_Initialize()
{
    ECode ec = NOERROR;

    ec = AuraCriticalSection_Create(&s_hListLock);
    if (FAILED(ec)) {
        return ec;
    }
    for (Int32 i = 0; i < NAMED_HS_SLOTS; i++) {
        s_namedHashList[i].Initialize();
    }

    return ec;
}

void NamedObject::S_Destroy()
{
    if (NULL != s_hListLock) {
        AuraCriticalSection_Destroy(s_hListLock);
        s_hListLock = NULL;
    }

    return ;
}

ECode NamedObject::S_CreateObject(
        /* [in]  */ NamedObjectFactory * pFactory,
        /* [out] */ NamedObject ** ppNamedObj,
        /* [out] */ Boolean * pbAlreadyExisted)
{
    WString name = pFactory->GetName();
    ObjectType type = pFactory->GetType();
    NamedObject * pNamedObj = NULL;
    ECode ec = NOERROR;

    *pbAlreadyExisted = FALSE;
    Lock(s_hListLock);
    ec = _S_GetObject(name, &pNamedObj);
    if (SUCCEEDED(ec)) {
        if (type == pNamedObj->GetType()) {
            pNamedObj->GetObject()->AddRef();
            *ppNamedObj = pNamedObj;
            Unlock(s_hListLock);
            *pbAlreadyExisted = TRUE;
            return NOERROR;
        }
        else {
            ec = E_ALREADY_EXIST;
            goto ErrorExit;
        }
    }

    ec = pFactory->CreateNamedObject(&pNamedObj, pbAlreadyExisted);
    if (FAILED(ec)) {
        goto ErrorExit;
    }
    _S_AddObject(name, pNamedObj);
    Unlock(s_hListLock);

    *ppNamedObj = pNamedObj;

    return NOERROR;

ErrorExit:
    Unlock(s_hListLock);
    return ec;
}

ECode NamedObject::S_ResolveObject(
        /* [in]  */ NamedObjectFactory * pFactory,
        /* [in]  */ oid_t oid,
        /* [in]  */ NamedObject ** ppNamedObj)
{
    WString name = pFactory->GetName();
    NamedObject * pNamedObj = NULL;
    ECode ec = NOERROR;

    assert(!name.IsNullOrEmpty());
    assert(oid > 0);
    assert(NULL != ppNamedObj);

    Lock(s_hListLock);
    ec = _S_GetObject(name, &pNamedObj);
    if (SUCCEEDED(ec)) {
        // already existed in the process.
        assert(pFactory->GetType() == pNamedObj->GetType());
        assert(oid == pNamedObj->GetOid());
        pNamedObj->GetObject()->AddRef();
        *ppNamedObj = pNamedObj;
        Unlock(s_hListLock);
        return NOERROR;
    }

    ec = pFactory->ResolveNamedObject(oid, &pNamedObj);
    if (FAILED(ec)) {
        goto ErrorExit;
    }

    _S_AddObject(name, pNamedObj);
    Unlock(s_hListLock);

    *ppNamedObj = pNamedObj;

    return ec;

ErrorExit:
    Unlock(s_hListLock);
    return ec;
}

ECode NamedObject::S_DestroyObject(
        /* [in] */ NamedObjectFactory * pFactory,
        /* [in] */ oid_t oid)
{
    WString name = pFactory->GetName();
    ECode ec = NOERROR;

    Lock(s_hListLock);
    _S_DeleteObject(name);

    ec = pFactory->DestroyNamedObject(oid);
    Unlock(s_hListLock);

    return ec;
}

ECode NamedObject::_S_GetObject(
        /* [in] */  WString name,
        /* [out] */ NamedObject ** ppNamedObj)
{
    NamedObject * pNamedObj = NULL;
    DLinkNode * pHead = NULL;

    pHead = &s_namedHashList[NamedHashCode(name)];
    ForEachDLinkNode(NamedObject*, pNamedObj, pHead)
    {
        if (pNamedObj->CompareName(name)) {
            *ppNamedObj = pNamedObj;
            return NOERROR;
        }
    }

    return E_DOES_NOT_EXIST;
}

ECode NamedObject::_S_AddObject(
        /* [in]  */ WString name,
        /* [in]  */ NamedObject * pNamedObj)
{
    s_namedHashList[NamedHashCode(name)].InsertLast(pNamedObj);

    return NOERROR;
}

ECode NamedObject::_S_DeleteObject(
        /* [in] */ WString name)
{
    NamedObject * pNamedObj = NULL;
    DLinkNode * pHead = NULL;

    pHead = &s_namedHashList[NamedHashCode(name)];
    ForEachDLinkNode(NamedObject*, pNamedObj, pHead)
    {
        if (pNamedObj->CompareName(name)) {
            pNamedObj->Detach();
            return NOERROR;
        }
    }

    return E_DOES_NOT_EXIST;
}

